package com.hk.core.authentication.security;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.hk.commons.util.ByteConstants;
import com.hk.commons.util.CollectionUtils;
import com.hk.commons.util.StringUtils;
import com.hk.core.authentication.api.ClientAppInfo;
import com.hk.core.authentication.api.DeptInfo;
import com.hk.core.authentication.api.TenantInfo;
import com.hk.core.authentication.api.UserPrincipal;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.math.BigInteger;
import java.time.LocalDate;
import java.util.*;

/**
 * 使用 spring security 实现的当前用户实体
 *
 * @author kevin
 * @date 2017年12月21日下午5:45:54
 */
@NoArgsConstructor
@Accessors(chain = true)
public class SecurityUserPrincipal extends UserPrincipal implements UserDetails, CredentialsContainer {

    /**
     * 默认的角色前缀
     */
    public static final String ROLE_PREFIX = "ROLE_";

    /**
     * 用户密码
     */
    @Setter
    @JsonIgnore
    private String password;

    /**
     * 用户状态
     */
    @Setter
    @JsonIgnore
    private Byte userStatus;

    /**
     * 获取用户权限
     *
     * @return GrantedAuthorityList
     */
    @Override
    @JsonIgnore
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return toGrantedAuthority(getRoles(), getPermissions());
    }

    public static Collection<? extends GrantedAuthority> toGrantedAuthority(Collection<String> roles, Collection<String> permissions) {
        var authorityList = new ArrayList<GrantedAuthority>();
        if (CollectionUtils.isNotEmpty(roles)) {
            roles.forEach(role -> {
                if (!StringUtils.startsWith(role, ROLE_PREFIX)) {
                    role = ROLE_PREFIX + role;
                }
                authorityList.add(new SimpleGrantedAuthority(role));
            });
        }
        if (CollectionUtils.isNotEmpty(permissions)) {
            permissions.forEach(permission -> authorityList.add(new SimpleGrantedAuthority(permission)));
        }
        return authorityList;
    }

    @Override
    public String getPassword() {
        return password;
    }

    /**
     * <pre>
     * 这个方法的返回值作为唯一的用户，
     * 像websocket 一对一发消息时，会使用这个方法来判断发送给哪个用户，尽量和父类保持一致
     * </pre>
     */
    @Override
    @JsonIgnore
    public final String getUsername() {
        return super.getName();
    }

    /**
     * 用户不过期
     *
     * @return true
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 账户是否锁定
     *
     * @return true if userStatus is One.
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonLocked() {
        return null != userStatus && ByteConstants.ONE == userStatus;
    }

    /**
     * 密码是否不过期
     *
     * @return true
     */
    @Override
    @JsonIgnore
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 账户是否可用
     *
     * @return true if userStatus is One.
     */
    @Override
    @JsonIgnore
    public boolean isEnabled() {
        return Objects.nonNull(userStatus) && ByteConstants.ONE == userStatus;
    }

    /**
     * 删除用户凭证信息，只有在登陆成功后才会调用
     *
     * @see org.springframework.security.authentication.ProviderManager#eraseCredentialsAfterAuthentication
     * 是否删除凭证信息，默认为 true
     * @see org.springframework.security.authentication.ProviderManager#authenticate(Authentication) 第 218 行
     */
    @Override
    public void eraseCredentials() {
        password = null;
    }

    @Override
    public SecurityUserPrincipal setUserId(Long userId) {
        super.setUserId(userId);
        return this;
    }

    @Override
    public SecurityUserPrincipal setAccount(String account) {
        super.setAccount(account);
        return this;
    }

    @Override
    public SecurityUserPrincipal setRealName(String realName) {
        super.setRealName(realName);
        return this;
    }

    @Override
    public SecurityUserPrincipal setUserType(Byte userType) {
        super.setUserType(userType);
        return this;
    }

    @Override
    public SecurityUserPrincipal setAreaCode(Integer areaCode) {
        super.setAreaCode(areaCode);
        return this;
    }

    @Override
    public SecurityUserPrincipal setMobileNumber(String mobileNumber) {
        super.setMobileNumber(mobileNumber);
        return this;
    }

    @Override
    public SecurityUserPrincipal setEmail(String email) {
        super.setEmail(email);
        return this;
    }

    @Override
    public SecurityUserPrincipal setGender(Byte gender) {
        super.setGender(gender);
        return this;
    }

    @Override
    public SecurityUserPrincipal setIconPath(String iconPath) {
        super.setIconPath(iconPath);
        return this;
    }

    @Override
    public SecurityUserPrincipal setDataRule(BigInteger dataRule) {
        super.setDataRule(dataRule);
        return this;
    }

    @Override
    public SecurityUserPrincipal setAppInfo(ClientAppInfo appInfo) {
        super.setAppInfo(appInfo);
        return this;
    }

    @Override
    public SecurityUserPrincipal setOrgId(Long orgId) {
        super.setOrgId(orgId);
        return this;
    }

    @Override
    public SecurityUserPrincipal setOrgName(String orgName) {
        super.setOrgName(orgName);
        return this;
    }

    @Override
    public SecurityUserPrincipal setDeptInfos(Set<DeptInfo> deptInfos) {
        super.setDeptInfos(deptInfos);
        return this;
    }

    @Override
    public SecurityUserPrincipal setBirth(LocalDate birth) {
        super.setBirth(birth);
        return this;
    }

    @Override
    public SecurityUserPrincipal setAdditionalInfo(Map<String, String> additionalInfo) {
        super.setAdditionalInfo(additionalInfo);
        return this;
    }

    @Override
    public SecurityUserPrincipal setRoles(Set<String> roles) {
        super.setRoles(roles);
        return this;
    }

    @Override
    public SecurityUserPrincipal setPermissions(Set<String> permissions) {
        super.setPermissions(permissions);
        return this;
    }

    @Override
    public SecurityUserPrincipal setTenantInfo(TenantInfo tenantInfo) {
        super.setTenantInfo(tenantInfo);
        return this;
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}
